/*
 *  Copyright 2013 National Institute of Advanced Industrial Science and Technology
 *  
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *  
 *      http://www.apache.org/licenses/LICENSE-2.0
 *  
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package org.sss.complex;

import java.io.ByteArrayInputStream;
import java.io.StringWriter;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.sss.common.SssServerRemote;
import org.sss.mapreduce.Cluster;
import org.sss.mapreduce.DBFactory;
import org.sss.server.SssServerConfiguration;
import org.sss.server.SssServerImpl;
import org.sss.server.SssServerResource;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

public class ComplexTestBase {
  private List<SssServerRemote> servers = null;
  private Cluster cluster = null;

  public static class TestServerConf {
    public final int id;
    public final int port;
    public final DBFactory dbFactory;

    public TestServerConf(int id, int port, DBFactory dbf) {
      this.id         = id;
      this.port       = port;
      this.dbFactory  = dbf;
    }
  }

  protected void startServers(TestServerConf... confs) throws Exception {
    assert servers == null;
    servers = new ArrayList<SssServerRemote>();
    String clusterConf = genClusterConf(Arrays.asList(confs));
    ByteArrayInputStream is = new ByteArrayInputStream(clusterConf.getBytes("utf-8"));
    this.cluster = Cluster.loadClusterConf("<in source>", is);

    for (TestServerConf conf: confs) {
      SssServerConfiguration sssConf = new SssServerConfiguration();
      sssConf.setServerId(conf.id);
      sssConf.ioConf.db_factory = conf.dbFactory;

      SssServerResource res = new SssServerResource(sssConf, cluster);

      Registry registry = LocateRegistry.createRegistry(conf.port);
      SssServerRemote server = new SssServerImpl(registry, res);
      registry.bind("SssServerImpl", server);
      servers.add(server);
    }
  }

  protected void stopServers() throws Exception {
    for (SssServerRemote s: servers) {
      s.shutdown();
    }
    this.servers = null;
  }

  protected Cluster getCluster() {
    return cluster;
  }

  private Element createElement(Document doc, String tag, String text) {
    Element elm = doc.createElement(tag);
    elm.appendChild(doc.createTextNode(text));
    return elm;
  }

  private String genClusterConf(List<TestServerConf> confs) throws Exception {
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    DocumentBuilder db = dbf.newDocumentBuilder();
    Document document = db.newDocument();

    Element root = document.createElement("cluster");
    document.appendChild(root);

    for (TestServerConf conf: confs) {
      int port = conf.port;
      Element worker = document.createElement("worker");
      root.appendChild(worker);

      worker.appendChild(createElement(document, "host", "localhost"));
      worker.appendChild(createElement(document, "port", "" + port));

      Element storage = document.createElement("storage");
      storage.appendChild(createElement(document, "protocol", "aistsss"));
      storage.appendChild(createElement(document, "host",     "localhost"));
      storage.appendChild(createElement(document, "port",     "" + port));
      worker.appendChild(storage);
    }
    Transformer transformer = TransformerFactory.newInstance().newTransformer();

    DOMSource source = new DOMSource(document);
    StringWriter writer = new StringWriter();
    StreamResult result = new StreamResult(writer);
    transformer.transform(source, result);  
    return writer.toString();
  }
}


